{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Introduction to atomman: Unit conversions\n",
    "\n",
    "__Lucas M. Hale__, [lucas.hale@nist.gov](mailto:lucas.hale@nist.gov?Subject=ipr-demo), _Materials Science and Engineering Division, NIST_.\n",
    "    \n",
    "[Disclaimers](http://www.nist.gov/public_affairs/disclaimer.cfm) "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 1. Introduction <a id='section1'></a>\n",
    "\n",
    "The atomman.unitconvert submodule includes tools for handling unit conversions within calculations. The unitconvert module is built around the [numericalunits](https://pypi.python.org/pypi/numericalunits) package, extending it with useful functions and tools.\n",
    "\n",
    "Units are handled in the following manner:\n",
    "\n",
    "1. Parameters are 'set' using functions that take value(s) and unit fields. The functions convert the values to common working units.\n",
    "\n",
    "2. All calculations are performed in the compatible working units.\n",
    "\n",
    "3. When finished, 'get' functions convert values from the working units to whatever units you want.\n",
    "\n",
    "Note that units are *not* tracked throughout the calculation, only conversions are performed at the beginning and end.  This is advantageous as calculations and functions can be implemented without caring about the units, and there is no extra overhead.  The disadvantage is that there is no explicit checking of compatible conversions, although implicit checking is possible (see [Section #4](#section4), or the [numericalunits](https://pypi.python.org/pypi/numericalunits) documentation.)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Library Imports**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "atomman version = 1.4.0\n",
      "Notebook executed on 2021-08-03\n"
     ]
    }
   ],
   "source": [
    "# Standard Python libraries\n",
    "import datetime\n",
    "\n",
    "# http://www.numpy.org/\n",
    "import numpy as np\n",
    "\n",
    "# https://github.com/usnistgov/atomman\n",
    "import atomman as am\n",
    "import atomman.unitconvert as uc\n",
    "\n",
    "# Show atomman version\n",
    "print('atomman version =', am.__version__)\n",
    "\n",
    "# Show date of Notebook execution\n",
    "print('Notebook executed on', datetime.date.today())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 2. Basics <a id='section2'></a>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 2.1. unit dictionary\n",
    "\n",
    "The unit dictionary stores all units defined by [numericalunits](https://pypi.python.org/pypi/numericalunits). This keeps the namespace clean and allows for units to be accessed by string."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "['pi', 'm', 'kg', 's', 'C', 'K', 'cm', 'mm', 'um', 'nm', 'pm', 'fm', 'km', 'angstrom', 'Å', 'lightyear', 'astro_unit', 'pc', 'kpc', 'Mpc', 'Gpc', 'inch', 'foot', 'mile', 'thou', 'L', 'mL', 'uL', 'nL', 'pL', 'fL', 'aL', 'kL', 'ML', 'GL', 'ms', 'us', 'ns', 'ps', 'fs', 'minute', 'hour', 'day', 'week', 'year', 'Hz', 'mHz', 'kHz', 'MHz', 'GHz', 'THz', 'PHz', 'rtHz', 'rpm', 'Hz·2π', 'mHz·2π', 'kHz·2π', 'MHz·2π', 'GHz·2π', 'THz·2π', 'PHz·2π', 'rpm·2π', 'g', 'mg', 'ug', 'ng', 'pg', 'fg', 'tonne', 'amu', 'Da', 'kDa', 'lbm', 'J', 'mJ', 'uJ', 'nJ', 'pJ', 'fJ', 'kJ', 'MJ', 'GJ', 'erg', 'eV', 'meV', 'keV', 'MeV', 'GeV', 'TeV', 'btu', 'smallcal', 'kcal', 'Wh', 'kWh', 'NA', 'mol', 'mmol', 'umol', 'nmol', 'pmol', 'fmol', 'M', 'mM', 'uM', 'nM', 'pM', 'fM', 'N', 'mN', 'uN', 'nN', 'pN', 'fN', 'kN', 'MN', 'GN', 'dyn', 'lbf', 'Pa', 'hPa', 'kPa', 'MPa', 'GPa', 'bar', 'mbar', 'cbar', 'dbar', 'kbar', 'Mbar', 'atm', 'torr', 'mtorr', 'psi', 'W', 'mW', 'uW', 'nW', 'pW', 'kW', 'MW', 'GW', 'TW', 'horsepower_imperial', 'horsepower_metric', 'Gal', 'mGal', 'uGal', 'eotvos', 'degFinterval', 'degCinterval', 'mK', 'uK', 'nK', 'pK', 'mC', 'uC', 'nC', 'Ah', 'mAh', 'A', 'mA', 'uA', 'nA', 'pA', 'fA', 'V', 'mV', 'uV', 'nV', 'kV', 'MV', 'GV', 'TV', 'ohm', 'mohm', 'kohm', 'Mohm', 'Gohm', 'Ω', 'mΩ', 'kΩ', 'MΩ', 'GΩ', 'S', 'mS', 'uS', 'nS', 'T', 'mT', 'uT', 'nT', 'G', 'mG', 'uG', 'kG', 'Oe', 'Wb', 'F', 'uF', 'nF', 'pF', 'fF', 'aF', 'H', 'mH', 'uH', 'nH', 'c0', 'mu0', 'μ0', 'eps0', 'ε0', 'Z0', 'hPlanck', 'hbar', 'ħ', 'kB', 'GNewton', 'sigmaSB', 'σSB', 'alphaFS', 'αFS', 'Rgas', 'e', 'uBohr', 'uNuc', 'aBohr', 'me', 'mp', 'mn', 'Rinf', 'Ry', 'Hartree', 'ARichardson', 'Phi0', 'KJos', 'RKlitz', 'REarth', 'g0', 'Msolar', 'MEarth']\n"
     ]
    }
   ],
   "source": [
    "print(list(uc.unit.keys()))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 2.2. Working units\n",
    "\n",
    "By default, atomman defines working units in:\n",
    "    \n",
    "- length = 'angstrom' = 'Å'\n",
    "\n",
    "- mass = 'amu'\n",
    "\n",
    "- energy = 'eV'\n",
    "\n",
    "- charge = 'e'\n",
    "\n",
    "- temperature = 'K'\n",
    "\n",
    "All other units are derived relative to these."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "angstrom = 1.0\n",
      "amu =      1.0\n",
      "eV =       1.0\n",
      "e =        1.0\n",
      "K =        1.0\n",
      "nm =       10.0\n",
      "g =        6.022140762081123e+23\n",
      "J =        6.241509074460763e+18\n",
      "ps =       98.22694750253277\n"
     ]
    }
   ],
   "source": [
    "print('angstrom =', uc.unit['angstrom'])\n",
    "print('amu =     ', uc.unit['amu'])\n",
    "print('eV =      ', uc.unit['eV'])\n",
    "print('e =       ', uc.unit['e'])\n",
    "print('K =       ', uc.unit['K'])\n",
    "print('nm =      ', uc.unit['nm'])\n",
    "print('g =       ', uc.unit['g'])\n",
    "print('J =       ', uc.unit['J'])\n",
    "print('ps =      ', uc.unit['ps'])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 2.3. reset_units()\n",
    "\n",
    "The working units can be altered using reset_units(). You can specify up to four out of five of length, mass, time, energy, and charge. If less than four values are given, SI units are used. Temperature is always 'K' when values are specified."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "angstrom = 0.09999999999999999\n",
      "amu =      1.6605390666e-24\n",
      "eV =       1.6021766339999996e-22\n",
      "e =        1.602176634e-19\n",
      "K =        1.0\n",
      "nm =       0.9999999999999999\n",
      "g =        1.0\n",
      "J =        0.0009999999999999998\n",
      "ps =       1.0\n"
     ]
    }
   ],
   "source": [
    "# Reset working units such that length is in 'nm', mass is in 'g' and time is in 'ps'\n",
    "uc.reset_units(length='nm', mass='g', time='ps')\n",
    "\n",
    "print('angstrom =', uc.unit['angstrom'])\n",
    "print('amu =     ', uc.unit['amu'])\n",
    "print('eV =      ', uc.unit['eV'])\n",
    "print('e =       ', uc.unit['e'])\n",
    "print('K =       ', uc.unit['K'])\n",
    "print('nm =      ', uc.unit['nm'])\n",
    "print('g =       ', uc.unit['g'])\n",
    "print('J =       ', uc.unit['J'])\n",
    "print('ps =      ', uc.unit['ps'])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Alternatively, if you call reset_units without arguments it will use the default numericalunits option and generate random working units.  This can be useful for debugging code (see [Section #4](#section4), or the [numericalunits](https://pypi.python.org/pypi/numericalunits) documentation)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "angstrom = 7.696109170941963e-10\n",
      "amu =      2.6118742271889054e-26\n",
      "eV =       8.256556200447549e-13\n",
      "e =        2.553057328163498e-21\n",
      "K =        17.994767005282004\n",
      "nm =       7.696109170941964e-09\n",
      "g =        0.01572907424898344\n",
      "J =        5153337.044888865\n",
      "ps =       1.3445548607246745e-14\n"
     ]
    }
   ],
   "source": [
    "# Reset working units to random values\n",
    "uc.reset_units()\n",
    "\n",
    "print('angstrom =', uc.unit['angstrom'])\n",
    "print('amu =     ', uc.unit['amu'])\n",
    "print('eV =      ', uc.unit['eV'])\n",
    "print('e =       ', uc.unit['e'])\n",
    "print('K =       ', uc.unit['K'])\n",
    "print('nm =      ', uc.unit['nm'])\n",
    "print('g =       ', uc.unit['g'])\n",
    "print('J =       ', uc.unit['J'])\n",
    "print('ps =      ', uc.unit['ps'])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Return working units to atomman's default\n",
    "uc.reset_units(length='angstrom', mass='amu', energy='eV', charge='e')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 2.4. Setting and getting static values\n",
    "\n",
    "Static numerical values can be set and get in one of two ways:\n",
    "\n",
    "- set by multiplying value by units, and get by dividing by units.\n",
    "\n",
    "- use the set_in_units() and get_in_units() functions."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 2.4.1. Direct setting and getting"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "10 angstrom^3 =\n",
      "0.01 nm^3\n"
     ]
    }
   ],
   "source": [
    "# Convert volume from angstrom^3 to nm^3\n",
    "print('10 angstrom^3 =')\n",
    "volume = 10 * uc.unit['angstrom']**3\n",
    "\n",
    "print(volume / uc.unit['nm']**3, 'nm^3')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "5.5 kg/(m*s^2) =\n",
      "5.5 Pa\n"
     ]
    }
   ],
   "source": [
    "# Show Pa = kg/(m*s^2)\n",
    "print('5.5 kg/(m*s^2) =')\n",
    "pressure = 5.5 * uc.unit['kg'] / (uc.unit['m']*uc.unit['s']**2)\n",
    "\n",
    "print(pressure / uc.unit['Pa'], 'Pa')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[1100. 1200. 1300.]\n",
      " [1200. 2200. 2300.]\n",
      " [1300. 2300. 3300.]] MPa\n"
     ]
    }
   ],
   "source": [
    "# Show that conversions work with arrays\n",
    "stress = np.array([[1.1, 1.2, 1.3],\n",
    "                   [1.2, 2.2, 2.3],\n",
    "                   [1.3, 2.3, 3.3]]) * uc.unit['GPa']\n",
    "\n",
    "print(stress / uc.unit['MPa'], 'MPa')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 2.4.2. parse()\n",
    "\n",
    "As the above example shows, expressing complex units can get messy and unclear. The parse() function makes this easier by allowing complex units to be parsed from strings."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "10 angstrom^3 =\n",
      "0.01 nm^3\n"
     ]
    }
   ],
   "source": [
    "# Convert volume from angstrom^3 to nm^3\n",
    "print('10 angstrom^3 =')\n",
    "volume = 10 * uc.parse('angstrom^3')\n",
    "\n",
    "print(volume / uc.parse('nm^3'), 'nm^3')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "5.5 kg/(m*s^2) =\n",
      "5.5 Pa\n"
     ]
    }
   ],
   "source": [
    "# Show Pa = kg/(m*s^2)\n",
    "print('5.5 kg/(m*s^2) =')\n",
    "pressure = 5.5 * uc.parse('kg/(m*s^2)')\n",
    "\n",
    "print(pressure / uc.parse('Pa'), 'Pa')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 2.4.3. set_in_units() and get_in_units()\n",
    "\n",
    "Both functions take a value and a unit string, call parse on the unit string and perform the correct * or /."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "10 angstrom^3 =\n",
      "0.01 nm^3\n"
     ]
    }
   ],
   "source": [
    "# Convert volume from angstrom^3 to nm^3\n",
    "print('10 angstrom^3 =')\n",
    "volume = uc.set_in_units(10, 'angstrom^3')\n",
    "\n",
    "print(uc.get_in_units(volume, 'nm^3'), 'nm^3')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "5.5 kg/(m*s^2) =\n",
      "5.5 Pa\n"
     ]
    }
   ],
   "source": [
    "# Show Pa = kg/(m*s^2)\n",
    "print('5.5 kg/(m*s^2) =')\n",
    "pressure = uc.set_in_units(5.5, 'kg/(m*s^2)')\n",
    "\n",
    "print(uc.get_in_units(pressure, 'Pa'), 'Pa')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[1100. 1200. 1300.]\n",
      " [1200. 2200. 2300.]\n",
      " [1300. 2300. 3300.]] MPa\n"
     ]
    }
   ],
   "source": [
    "# Show that conversions work with arrays\n",
    "stress = uc.set_in_units(np.array([[1.1, 1.2, 1.3],\n",
    "                                   [1.2, 2.2, 2.3],\n",
    "                                   [1.3, 2.3, 3.3]]), 'GPa')\n",
    "\n",
    "print(uc.get_in_units(stress, 'MPa'), 'MPa')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 2.5. set_literal()\n",
    "\n",
    "Values can also be read in from strings with set_literal()."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "10 angstrom^3 =\n",
      "0.01 nm^3\n"
     ]
    }
   ],
   "source": [
    "# Convert volume from angstrom^3 to nm^3\n",
    "print('10 angstrom^3 =')\n",
    "volume = uc.set_literal('10 angstrom^3')\n",
    "\n",
    "print(uc.get_in_units(volume, 'nm^3'), 'nm^3')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[1100. 1200. 1300.]\n",
      " [1200. 2200. 2300.]\n",
      " [1300. 2300. 3300.]] MPa\n"
     ]
    }
   ],
   "source": [
    "# Show that conversions work with arrays\n",
    "stress = uc.set_literal(\"\"\"[[1.1, 1.2, 1.3], \n",
    "                            [1.2, 2.2, 2.3], \n",
    "                            [1.3, 2.3, 3.3]] GPa\"\"\")\n",
    "\n",
    "print(uc.get_in_units(stress, 'MPa'), 'MPa')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 3. Data model representations <a id='section3'></a>\n",
    "\n",
    "In addition to the basic conversions, unitconvert also allows for the values to be returned as and extracted from a [DataModelDict](https://github.com/usnistgov/DataModelDict). This provides a means of representing the data equivalently in either JSON or XML."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 3.1. model()\n",
    "\n",
    "Values can be converted into a structured data model using model()."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<value>40.0</value><unit>angstrom</unit>\n"
     ]
    }
   ],
   "source": [
    "# Set length as 4 nm\n",
    "length = uc.set_in_units(4, 'nm')\n",
    "\n",
    "# Transform length into a model with units in angstrom\n",
    "lmodel = uc.model(length, 'angstrom')\n",
    "\n",
    "# Print lmodel as XML\n",
    "print(lmodel.xml(full_document=False))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{\n",
      "  \"value\": [\n",
      "    10.0,\n",
      "    20.0,\n",
      "    30.0,\n",
      "    40.0,\n",
      "    50.0\n",
      "  ],\n",
      "  \"unit\": \"K\"\n",
      "}\n"
     ]
    }
   ],
   "source": [
    "# Set list of temperatures in K\n",
    "temperatures = uc.set_in_units([10,20,30,40,50], 'K')\n",
    "\n",
    "# Transform temperatures into a model with units in K\n",
    "tmodel = uc.model(temperatures, 'K')\n",
    "\n",
    "# Print tmodel as JSON\n",
    "print(tmodel.json(indent=2))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "For equivalent JSON/XML representation, values with 2 or more dimensions are flattened and the shape is included in the model."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{\"value\": [1100.0000000000002, 0.0, 0.0, 0.0, 2000.0000000000002, 500.00000000000006, 0.0, 500.00000000000006, -1400.0], \"shape\": [3, 3], \"unit\": \"kPa\"}\n",
      "\n",
      "<value>1100.0000000000002</value><value>0.0</value><value>0.0</value><value>0.0</value><value>2000.0000000000002</value><value>500.00000000000006</value><value>0.0</value><value>500.00000000000006</value><value>-1400.0</value><shape>3</shape><shape>3</shape><unit>kPa</unit>\n"
     ]
    }
   ],
   "source": [
    "# Set stress tensor in 'MPa'\n",
    "stress = uc.set_in_units(np.array([[1.1, 0.0, 0.0],\n",
    "                                   [0.0, 2.0, 0.5],\n",
    "                                   [0.0, 0.5, -1.4]]), 'MPa')\n",
    "                         \n",
    "# Transform stress into a model with units in kPa\n",
    "smodel = uc.model(stress, 'kPa')\n",
    "\n",
    "# Print smodel as JSON\n",
    "print(smodel.json())\n",
    "print()\n",
    "\n",
    "# Print smodel as XML\n",
    "print(smodel.xml(full_document=False))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 3.2. value_unit()\n",
    "\n",
    "Values can then be read back in from a model, XML or JSON using value_unit()."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "4.0 nm\n"
     ]
    }
   ],
   "source": [
    "# Read lmode to set length\n",
    "length = uc.value_unit(lmodel)\n",
    "\n",
    "# Print length in nm\n",
    "print(uc.get_in_units(length, 'nm'), 'nm')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[10. 20. 30. 40. 50.] K\n"
     ]
    }
   ],
   "source": [
    "# Read tmodel to set temperatures \n",
    "temperatures = uc.value_unit(tmodel)\n",
    "\n",
    "# Print temperatures in K\n",
    "print(uc.get_in_units(temperatures, 'K'), 'K')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[ 1.1  0.   0. ]\n",
      " [ 0.   2.   0.5]\n",
      " [ 0.   0.5 -1.4]] MPa\n"
     ]
    }
   ],
   "source": [
    "# Read smodel to set stress \n",
    "stress = uc.value_unit(smodel)\n",
    "\n",
    "# Print stress in 'MPa'\n",
    "print(uc.get_in_units(stress, 'MPa'), 'MPa')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 3.3. error_unit()\n",
    "\n",
    "Standard errors associated with each given value can also be included in the model, which can then be retrieved using error_unit()."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{\n",
      "  \"value\": [\n",
      "    0.010651321102400925,\n",
      "    0.01952841980711606,\n",
      "    0.029566301223510026,\n",
      "    0.03929124802721068,\n",
      "    0.050565258987151245\n",
      "  ],\n",
      "  \"error\": [\n",
      "    0.0020648408214520254,\n",
      "    0.0020071356639923474,\n",
      "    0.001994890695467289,\n",
      "    0.002012491668659884,\n",
      "    0.0020967486040513543\n",
      "  ],\n",
      "  \"unit\": \"m\"\n",
      "}\n"
     ]
    }
   ],
   "source": [
    "# Generate realistic-looking nonsense\n",
    "xcoordinate = np.array([1, 2, 3, 4, 5]) + 0.2 * np.random.rand(5) - 0.1\n",
    "xcoorderror = np.array([0.2, 0.2, 0.2, 0.2, 0.2]) + 0.02 * np.random.rand(5) - 0.01\n",
    "\n",
    "# Assign units to nonsense\n",
    "xcoordinate = uc.set_in_units(xcoordinate, 'cm')\n",
    "xcoorderror = uc.set_in_units(xcoorderror, 'cm')\n",
    "\n",
    "# Generate model of nonsense with error\n",
    "model = uc.model(xcoordinate, 'm', error=xcoorderror)\n",
    "print(model.json(indent=2))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Errors can then be similarly extracted from the model using error_unit()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "value = [10.6513211  19.52841981 29.56630122 39.29124803 50.56525899] mm\n",
      "error = [2.06484082 2.00713566 1.9948907  2.01249167 2.0967486 ] mm\n"
     ]
    }
   ],
   "source": [
    "# Read realistic-looking nonsense back in\n",
    "print('value =', uc.get_in_units(uc.value_unit(model), 'mm'), 'mm')\n",
    "print('error =', uc.get_in_units(uc.error_unit(model), 'mm'), 'mm')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 4. Unit debugging <a id='section4'></a>\n",
    "\n",
    "There is no explicit unit control with unitconvert, but correct unit conversions can still be debugged and tested by seeing if changing the working units changes values."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "57 atm = 0.005775525 GPa\n",
      "57 atm = 0.005775525 GPa\n"
     ]
    }
   ],
   "source": [
    "# Print valid conversion\n",
    "print('57 atm =', end=' ')\n",
    "time = uc.set_in_units(57, 'atm')\n",
    "print(uc.get_in_units(time, 'GPa'), 'GPa')\n",
    "\n",
    "# Reset working units to random values\n",
    "uc.reset_units()\n",
    "\n",
    "# Print valid conversion again showing same results\n",
    "print('57 atm =', end=' ')\n",
    "time = uc.set_in_units(57, 'atm')\n",
    "print(uc.get_in_units(time, 'GPa'), 'GPa')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "57 s = 0.001004272682617313 GPa\n",
      "57 s = 0.00010882989890990457 GPa\n"
     ]
    }
   ],
   "source": [
    "# Print invalid conversion\n",
    "print('57 s =', end=' ')\n",
    "time = uc.set_in_units(57, 's')\n",
    "print(uc.get_in_units(time, 'GPa'), 'GPa')\n",
    "\n",
    "# Reset working units to random values\n",
    "uc.reset_units()\n",
    "\n",
    "# Print invalid conversion again showing different results\n",
    "print('57 s =', end=' ')\n",
    "time = uc.set_in_units(57, 's')\n",
    "print(uc.get_in_units(time, 'GPa'), 'GPa')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    " "
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.4"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
